/*
 * Copyright 2008 Max Kugland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.splink.resource {
	import org.splink.library.distributor.Distributor;
	import org.splink.library.loading.QLoader;
	import org.splink.library.loading.QUrlLoader;
	import org.splink.library.queue.IQ;
	import org.splink.library.queue.IQable;
	import org.splink.library.queue.Q;
	import org.splink.library.queue.QEvent;
	import org.splink.resource.resourcebundles.LibrariesData;
	import org.splink.resource.resourcebundles.ResourcebundleData;
	import org.splink.resource.resourcebundles.libraries.LibraryData;
	import org.splink.resource.resourcebundles.resourcebundle.assets.AssetData;
	import org.splink.resource.resourcebundles.resourcebundle.files.FileData;
	import org.splink.resource.resourcebundles.resourcebundle.fonts.FontData;

	import flash.net.URLRequest;
	import flash.system.LoaderContext;

	/**
	 * Loads all resources declared within a <code>ResourcebundleData</code> and populates 
	 * <code>ResourceProvider</code> with the loaded resources.
	 * 
	 * @author Max Kugland
	 */
	internal class ResourcebundleLoader extends Distributor implements IQable {
		private var _bundle : ResourcebundleData;
		private var _loaderContext : LoaderContext;
		private var _progressProcessor : ResourceProgressProcessor;
		private var _librariesData : LibrariesData;
		private var _queue : IQ;
		private var _provider : ResourceProvider;

		/**
		 * @param bundle the <code>ResourcebundleData</code> defining the resources to load
		 * @param applicationDomain the ApplicationDomain to load the resources into
		 */
		public function ResourcebundleLoader(bundle : ResourcebundleData, librariesData : LibrariesData, loaderContext : LoaderContext) {
			_provider = ResourceProvider(ResourceProvider.instance());
			_bundle = bundle;
			_librariesData = librariesData;
			_loaderContext = loaderContext;
			_queue = new Q();
		}

		/**
		 * @inheritDoc
		 */
		public function get id() : String {
			return _bundle.locale;
		}

		/**
		 * @inheritDoc
		 */
		public function start() : void {
			_progressProcessor = new ResourceProgressProcessor(_bundle, _librariesData);
			
			_queue.register(QEvent.COMPLETE, onComplete);
			_queue.register(QEvent.PROGRESS, onProgress);			_queue.register(QEvent.ERROR, onError);
			
			_queue.add(createAssetQueue());
			_queue.add(createFontQueue());
			_queue.add(createFileQueue());
			_queue.add(createLibraryQueue());
			
			_queue.start();
		}

		/**
		 * @inheritDoc
		 */
		public function stop() : void {
			_queue.stop();
		}

		/**
		 * @inheritDoc
		 */
		public function reset() : void {
			_queue.reset();
		}

		private function createLibraryQueue() : IQable {
			var a : Array = new Array();
			var libraries : Array = _librariesData ? _librariesData.libraryDataArray : [];
			var path : String = _librariesData ? _librariesData.path : "";
			
			var q : IQ = new Q();
			q.register(QEvent.COMPLETE, function(e : QEvent):void {
				if(a.length > 0) {
					_provider.setLibrarys(a);
				}
			});
			
			for each (var library : LibraryData in libraries) {
				var libraryLoader : IQable = new QLoader(new URLRequest(path + library.src), _loaderContext, library.id);
				q.add(libraryLoader).register(QEvent.COMPLETE, function(e : QEvent):void {
					a.push(new PreparedLibraryData(e.id, (e.source as QLoader).getContent()));
				});
			}
			return q;
		}

		private function createAssetQueue() : IQable {
			var assets : Array = _bundle.assetsData ? _bundle.assetsData.assetDataArray : []; 
			var path : String = _bundle.assetsData ? _bundle.assetsData.path : "";
			
			var q : IQ = new Q();
			q.register(QEvent.COMPLETE, function(e : QEvent) : void {
				var assets : Array = new Array();
				for (var i : int = 0;i < q.length;i++) {
					assets = assets.concat(new AssetRegistrar().register(QLoader(q.getAt(i)).getContent()));
				}
				_provider.setAssets(assets);
			});
			
			for each (var asset : AssetData in assets) {
				q.add(new QLoader(new URLRequest(path + asset.src), _loaderContext, asset.id));
			}
			return q;
		}

		private function createFontQueue() : IQable {
			var fonts : Array = _bundle.fontsData ? _bundle.fontsData.fontDataArray : [];
			var path : String = _bundle.fontsData ? _bundle.fontsData.path : ""; 
			
			var q : IQ = new Q();
			for each (var font : FontData in fonts) {
				if(font.isSystemFont != true) {
					q.add(new QLoader(new URLRequest(path + font.src), _loaderContext, font.id)).register(QEvent.COMPLETE, function(e : QEvent):void {
						new FontRegistrar(QLoader(e.source).getContent(), _bundle.fontsData.getFontDataById(e.id));
					});
				}
			}
			_provider.setFonts(fonts);
			return q;
		}
		
		private function createFileQueue() : IQable {
			var a : Array = new Array();
			var files : Array = _bundle.filesData ? _bundle.filesData.fileDataArray : []; 
			var path : String = _bundle.filesData ? _bundle.filesData.path : "";
			
			var q : IQ = new Q();
			q.register(QEvent.COMPLETE, function(e : QEvent) : void {
				_provider.setFiles(a);
			});
			
			for each (var file : FileData in files) {
				q.add(new QUrlLoader(new URLRequest(path + file.src), file.fileType, file.id)).register(QEvent.COMPLETE, function(e : QEvent):void {
					a.push(new PreparedFileData(e.id, (e.source as QUrlLoader).getContent()));
				});
			}
			return q;
		}

		private function onError(e : QEvent) : void {
			distribute(e.clone(this));
		}

		private function onProgress(e : QEvent) : void {
			var progress : ResourceProgress = _progressProcessor.getProgressById(e.id, e.progress.current);
			if(progress) {
				distribute(e.clone(this));				distribute(new ResourceProcessorEvent(this, ResourceProcessorEvent.PROGRESS, progress));
			}
		}

		private function onComplete(e : QEvent) : void {
			e.source.finalize();
			distribute(e.clone(this));
		}

		/**
		 * @inheritDoc
		 */
		override public function finalize() : void {
			_queue.finalize();
			_queue = null;
			_bundle = null;
			_librariesData = null;
			_loaderContext = null;
			_progressProcessor.finalize();
			_progressProcessor = null;
			_loaderContext = null;
		}
	}
}